package com.kylin.domain.oauth2.social.wechat;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.kylin.domain.user.vo.WechatUserInfoVO;
import lombok.extern.slf4j.Slf4j;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.codehaus.xfire.util.Base64;
import org.springframework.stereotype.Component;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.security.AlgorithmParameters;
import java.security.Security;
import java.util.Arrays;
import java.util.Objects;

/**
 * 微信用户相关信息解析器
 * @author Damon S.
 * @version v1.0.1
 * @date 2020年11月20日 18:17
 */
@Slf4j
@Component
public final class WechatInterpreter {

    private static final ObjectMapper MAPPER = new ObjectMapper();

    private WechatInterpreter() {}

    /**
     * 解密用户敏感数据获取用户信息
     * @param data 用户加密数据
     * @return 返回解密的用户信息
     */
    public WechatUserInfoVO getUserInfo(EncryptedUserData data) {
        // 解密数据
        final byte[] resultByte = this.decryptUserData(data);

        WechatUserInfoVO userInfoVO = WechatUserInfoVO.EMPTY;
        // 判断结果是否合法
        if (Objects.isNull(resultByte) || resultByte.length < 1) {
            log.error("用户信息解析失败[encryptedData:{},sessionKey:{},iv:{}]",
                    data.getEncryptedData(), data.getSessionKey(), data.getIv());
            return userInfoVO;
        }
        // 解析用户数据对象
        try {
            userInfoVO = MAPPER.readValue(resultByte, WechatUserInfoVO.class);
        } catch (Exception e) {
            log.error("用户信息解析失败。", e);
        }
        return userInfoVO;
    }


    private byte[] decryptUserData(EncryptedUserData data) {
        // 偏移量
        byte[] ivByte = Base64.decode(data.getIv());
        // 被加密的数据
        byte[] dataByte =  Base64.decode(data.getEncryptedData());
        // 加密秘钥
        byte[] keyByte = Base64.decode(data.getSessionKey());

        // 如果密钥不足16位，那么就补足.  这个if 中的内容很重要
        int base = 16;
        if ((keyByte.length % base) != 0) {
            int groups = keyByte.length / base + 1;
            byte[] temp = new byte[groups * base];
            Arrays.fill(temp, (byte) 0);
            System.arraycopy(keyByte, 0, temp, 0, keyByte.length);
            keyByte = temp;
        }

        byte[] resultByte = new byte[0];
        try {
            // 初始化
            Security.addProvider(new BouncyCastleProvider());
            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding","BC");
            SecretKeySpec spec = new SecretKeySpec(keyByte, "AES");
            AlgorithmParameters parameters = AlgorithmParameters.getInstance("AES");
            parameters.init(new IvParameterSpec(ivByte));
            cipher.init(Cipher.DECRYPT_MODE, spec, parameters);
            resultByte = cipher.doFinal(dataByte);
        } catch (Exception e) {
            log.error("解析加密数据失败。", e);
        }
        return resultByte;
    }
}
